Skip to content

feat: 아티클 전체 조회 구현#22

Merged
rootTiket merged 8 commits intodevfrom
feat/#19
Jul 7, 2025
Merged

feat: 아티클 전체 조회 구현#22
rootTiket merged 8 commits intodevfrom
feat/#19

Conversation

@rootTiket
Copy link
Contributor

@rootTiket rootTiket commented Jul 7, 2025

🚀 PR 요약

아티클 전체 조회 기능 구현했습니다.

✨ PR 상세 내용

  1. 페이지네이션 처리는 클라이언트에서 요청 할 수 있도록 구현했습니다.
  2. 항상 최신순을 반환합니다.

🚨 주의 사항

스웨거에 localhost 지워져 있어서 추가했습니다

✅ 체크 리스트

  • 리뷰어 설정했나요?
  • Label 설정했나요?
  • 제목 양식 맞췄나요? (ex. feat: 기능 추가)
  • 변경 사항에 대한 테스트를 진행했나요?

close #19

Summary by CodeRabbit

  • New Features
    • Added a new API endpoint to retrieve a paginated list of articles for the authenticated user.
    • Articles in the paginated list include article ID, URL, memo, and read status.
    • Articles are sorted in descending order by creation date.
  • Documentation
    • Swagger documentation now includes both deployment and local server environments for easier API testing.
  • Tests
    • Added tests to verify correct pagination and sorting of articles in the new endpoint.

@rootTiket rootTiket requested a review from ose0221 July 7, 2025 17:02
@rootTiket rootTiket self-assigned this Jul 7, 2025
@rootTiket rootTiket added the FEAT label Jul 7, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 7, 2025

"""

Walkthrough

A paginated article retrieval feature was implemented, including a new GET endpoint for fetching a user's articles in descending creation order. Supporting repository, service, and DTO classes were added or extended to enable pagination and sorting. Swagger configuration was updated to include a local server, and corresponding tests were introduced.

Changes

File(s) Change Summary
.../domain/article/application/ArticleManagementUsecase.java Added getAllArticles method for paginated article retrieval by user.
.../domain/article/domain/repository/ArticleRepository.java, ArticleRepositoryCustom.java, ...Impl.java Extended repository to support custom paginated queries; introduced custom interface and implementation.
.../domain/article/domain/service/ArticleGetService.java Added findAll method delegating to custom repository for paginated fetch.
.../domain/article/presentation/ArticleController.java Added new GET /articles endpoint accepting pagination parameters.
.../domain/article/presentation/dto/response/ArticlesResponse.java Added ArticlesResponse record DTO with static factory method.
.../domain/article/presentation/dto/response/ArticleAllResponse.java Added ArticleAllResponse record DTO with static factory method.
.../global/config/swagger/SwaggerConfig.java Added local server to Swagger/OpenAPI configuration.
.../domain/article/application/ArticleManagementUsecaseTest.java Added tests for paginated retrieval and ordering of articles.
.../domain/fixture/TestFixture.java Added overloaded fixture method for creating articles with explicit URL.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant Usecase
    participant Service
    participant Repository

    Client->>Controller: GET /articles?pageNumber=&pageSize=
    Controller->>Usecase: getAllArticles(user, pageNumber, pageSize)
    Usecase->>Service: findAll(userId, PageRequest)
    Service->>Repository: findAllCustom(userId, Pageable)
    Repository-->>Service: Page<Article>
    Service-->>Usecase: Page<Article>
    Usecase-->>Controller: ArticleAllResponse (total, list)
    Controller-->>Client: ResponseDto<ArticleAllResponse>
Loading

Assessment against linked issues

Objective Addressed Explanation
Implement API for fetching all articles (latest first) with pagination (#19)
Ensure sorting is always by most recent (descending creation time) (#19)
Apply pagination to article retrieval (#19)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Addition of local server entry in SwaggerConfig.java (src/main/java/com/pinback/pinback_server/global/config/swagger/SwaggerConfig.java) This change updates API documentation configuration and is not related to the article retrieval objectives.

Suggested reviewers

  • ose0221

Poem

In the warren of code, new features appear,
Articles now fetch with paging so clear.
Latest first, just as planned,
Paginated lists right at your hand.
Swagger now knows both local and cloud—
This bunny hops forward, happy and proud!
🐇✨
"""

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/main/java/com/pinback/pinback_server/domain/article/domain/service/ArticleGetService.java (1)

31-33: Consider adding parameter validation for robustness.

The method implementation correctly delegates to the repository layer and maintains proper transaction semantics. However, consider adding null checks for the parameters to prevent potential NullPointerException at runtime.

 public Page<Article> findAll(UUID userId, PageRequest pageRequest) {
+	if (userId == null) {
+		throw new IllegalArgumentException("User ID cannot be null");
+	}
+	if (pageRequest == null) {
+		throw new IllegalArgumentException("Page request cannot be null");
+	}
 	return articleRepository.findAllCustom(userId, pageRequest);
 }
src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java (1)

48-54: Add parameter validation to prevent IllegalArgumentException.

The implementation is clean, but PageRequest.of() can throw IllegalArgumentException for invalid parameters. Consider adding validation or let the controller handle validation as suggested in the previous comment.

If you want to add validation at the use case level, apply this diff:

 public List<ArticlesResponse> getAllArticles(User user, int pageNumber, int pageSize) {
+    if (pageNumber < 0) {
+        throw new IllegalArgumentException("Page number must be non-negative");
+    }
+    if (pageSize <= 0) {
+        throw new IllegalArgumentException("Page size must be positive");
+    }
     Page<Article> articles = articleGetService.findAll(user.getId(), PageRequest.of(pageNumber, pageSize));
src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustomImpl.java (1)

27-43: Well-implemented custom repository with QueryDSL.

The implementation correctly handles pagination and ordering requirements. The use of a separate count query and PageableExecutionUtils.getPage is good for performance.

Consider whether the fetchJoin() on user is necessary since you're only filtering by user ID and the ArticlesResponse doesn't include user data:

 List<Article> articles = queryFactory
     .selectFrom(article)
-    .join(article.user, user).fetchJoin()
+    .join(article.user, user)
     .where(article.user.id.eq(userId))

This could improve performance by avoiding unnecessary data fetching.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d53e2b and 0953f1b.

📒 Files selected for processing (10)
  • src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java (3 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepository.java (1 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustom.java (1 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustomImpl.java (1 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/domain/service/ArticleGetService.java (2 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/presentation/ArticleController.java (2 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/presentation/dto/response/ArticlesResponse.java (1 hunks)
  • src/main/java/com/pinback/pinback_server/global/config/swagger/SwaggerConfig.java (1 hunks)
  • src/test/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecaseTest.java (3 hunks)
  • src/test/java/com/pinback/pinback_server/domain/fixture/TestFixture.java (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepository.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustom.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/presentation/ArticleController.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/domain/service/ArticleGetService.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/test/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecaseTest.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustomImpl.java (1)
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (7)
src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepositoryCustom.java (1)

10-12: LGTM! Clean custom repository interface design.

The interface follows Spring Data JPA custom repository conventions perfectly. The method signature is appropriate for paginated user-specific article retrieval.

src/main/java/com/pinback/pinback_server/global/config/swagger/SwaggerConfig.java (1)

24-27: LGTM! Good addition of local server configuration.

Adding the localhost server to the Swagger configuration improves developer experience by allowing API testing against both local and deployment environments. The implementation is clean and maintains the existing deployment server configuration.

src/main/java/com/pinback/pinback_server/domain/article/domain/repository/ArticleRepository.java (1)

10-10: LGTM! Correct Spring Data JPA custom repository pattern.

The repository properly extends both JpaRepository and ArticleRepositoryCustom, following the standard Spring Data pattern for integrating custom query methods. This maintains existing functionality while enabling the new paginated retrieval feature.

src/test/java/com/pinback/pinback_server/domain/fixture/TestFixture.java (1)

33-35: LGTM! Helpful test fixture method addition.

The new overloaded method provides flexibility for creating articles with specific URLs, which supports testing the new pagination functionality. The implementation is consistent with existing fixture methods, maintaining the same timestamp and memo patterns.

src/main/java/com/pinback/pinback_server/domain/article/domain/service/ArticleGetService.java (1)

3-6: LGTM! Proper imports for pagination support.

The new imports are appropriate for the pagination functionality being added.

src/main/java/com/pinback/pinback_server/domain/article/presentation/dto/response/ArticlesResponse.java (1)

1-17: LGTM! Clean DTO implementation with appropriate factory method.

The record structure is well-designed for the article listing use case, and the static factory method follows good practices for entity-to-DTO conversion.

src/test/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecaseTest.java (1)

97-142: Excellent test coverage for the pagination feature.

The tests comprehensively verify both pagination functionality and ordering requirements. The test setup is clean with proper data isolation, and the assertions are appropriate for validating the expected behavior.

Comment on lines 42 to 49
@GetMapping
public ResponseDto<List<ArticlesResponse>> getAll(@CurrentUser User user, @RequestParam int pageNumber,
@RequestParam int pageSize) {

List<ArticlesResponse> response = articleManagementUsecase.getAllArticles(user, pageNumber, pageSize);
return ResponseDto.ok(response);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for pagination parameters to prevent invalid requests.

The endpoint lacks validation for pageNumber and pageSize parameters, which could lead to runtime exceptions or performance issues with invalid values.

Apply this diff to add proper validation:

 @GetMapping
-public ResponseDto<List<ArticlesResponse>> getAll(@CurrentUser User user, @RequestParam int pageNumber,
-    @RequestParam int pageSize) {
+public ResponseDto<List<ArticlesResponse>> getAll(@CurrentUser User user, 
+    @RequestParam @Min(value = 0, message = "Page number must be non-negative") int pageNumber,
+    @RequestParam @Min(value = 1, message = "Page size must be positive") @Max(value = 100, message = "Page size must not exceed 100") int pageSize) {

Don't forget to add the import for validation annotations:

+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.Max;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@GetMapping
public ResponseDto<List<ArticlesResponse>> getAll(@CurrentUser User user, @RequestParam int pageNumber,
@RequestParam int pageSize) {
List<ArticlesResponse> response = articleManagementUsecase.getAllArticles(user, pageNumber, pageSize);
return ResponseDto.ok(response);
}
// add at top of file alongside other imports
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Max;
@GetMapping
public ResponseDto<List<ArticlesResponse>> getAll(@CurrentUser User user,
@RequestParam @Min(value = 0, message = "Page number must be non-negative") int pageNumber,
@RequestParam @Min(value = 1, message = "Page size must be positive")
@Max(value = 100, message = "Page size must not exceed 100") int pageSize) {
List<ArticlesResponse> response =
articleManagementUsecase.getAllArticles(user, pageNumber, pageSize);
return ResponseDto.ok(response);
}
🤖 Prompt for AI Agents
In
src/main/java/com/pinback/pinback_server/domain/article/presentation/ArticleController.java
around lines 42 to 49, the getAll method lacks validation for the pagination
parameters pageNumber and pageSize. To fix this, add validation annotations such
as @Min(1) to both parameters to ensure they are positive integers. Also, import
the necessary validation annotations from javax.validation.constraints. This
will prevent invalid requests and potential runtime errors.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/main/java/com/pinback/pinback_server/domain/article/presentation/dto/response/ArticleAllResponse.java (2)

5-8: Consider using plural form for the count field.

The field totalArticle represents a count of multiple articles, so totalArticles would be more semantically accurate and consistent with the articles field.

public record ArticleAllResponse(
-	long totalArticle,
+	long totalArticles,
	List<ArticlesResponse> articles
) {

9-14: LGTM with consideration for null safety.

The static factory method follows Java conventions and provides a clean way to create instances. Consider adding null checks or validation annotations if your project requires defensive programming practices.

If you want to add null safety:

public static ArticleAllResponse of(long totalArticle, List<ArticlesResponse> articles) {
+	Objects.requireNonNull(articles, "articles cannot be null");
	return new ArticleAllResponse(
		totalArticle,
		articles
	);
}

Don't forget to import java.util.Objects if you choose this approach.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51a71ac and c473efc.

📒 Files selected for processing (4)
  • src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java (3 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/presentation/ArticleController.java (2 hunks)
  • src/main/java/com/pinback/pinback_server/domain/article/presentation/dto/response/ArticleAllResponse.java (1 hunks)
  • src/test/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecaseTest.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/main/java/com/pinback/pinback_server/domain/article/presentation/ArticleController.java
  • src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java
  • src/test/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecaseTest.java
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: rootTiket
PR: Pinback-Team/pinback-server#18
File: src/main/java/com/pinback/pinback_server/domain/article/application/ArticleManagementUsecase.java:38-41
Timestamp: 2025-07-07T15:33:02.697Z
Learning: In the Pinback server project, article detail retrieval (getArticleDetail method) does not require user authorization checks. Articles can be accessed by ID without ownership verification as per the project's design decision.
🔇 Additional comments (1)
src/main/java/com/pinback/pinback_server/domain/article/presentation/dto/response/ArticleAllResponse.java (1)

1-3: LGTM!

Package declaration follows standard conventions and imports are minimal and appropriate.

Copy link
Contributor

@ose0221 ose0221 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다 👍👍👍

Comment on lines +27 to +35
public Page<Article> findAllCustom(UUID userId, Pageable pageable) {
List<Article> articles = queryFactory
.selectFrom(article)
.join(article.user, user).fetchJoin()
.where(article.user.id.eq(userId))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(article.createdAt.desc())
.fetch();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 구현하신 페이지네이션 방식은 offset 기반 외에도 cursor 기반이 있으니 시간이 될 때 공부하면 좋을 것 같습니당 💪💪💪

@rootTiket rootTiket merged commit 6c23ab8 into dev Jul 7, 2025
5 checks passed
@rootTiket rootTiket deleted the feat/#19 branch July 7, 2025 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 아티클 전체조회 구현

2 participants